#ifndef TOOLS_ENDIAN_H
#define TOOLS_ENDIAN_H

#include <type_traits>
#include <memory>
#include <cstring>

namespace Tool
{

constexpr inline bool IsLittleEndian()
{
#if defined(_WIN32) || defined(_WIN64)
    return true;
#elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)
        return true;
#elif defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__m68k__) || defined(__s390__) || defined(__sparc__)
        return false;
#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__)
    return __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__;
#else
// 保守处理：无法确定
#error "无法确定系统字节序，请手动配置或扩展 IsLittleEndian() 的检测逻辑"
#endif
}

template <typename T>
constexpr T ToBigEndian(T value)
{
    static_assert(std::is_trivial_v<T>, "仅支持平凡类型（Trivial Type）");
    static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,"仅支持 1/2/4/8 字节类型（MSVC constexpr 限制）");

    if constexpr (sizeof(T) == 1 || !IsLittleEndian())
    {
        return value;
    }
    else if constexpr (sizeof(T) == 2)
    {
        return static_cast<T>(
            ((value & 0x00FF) << 8)
            |((value & 0xFF00) >> 8));
    }
    else if constexpr (sizeof(T) == 4)
    {
        if constexpr (std::is_floating_point_v<T>)
        {
            // 浮点数：先转为整数，操作后再转回
            uint32_t temp;
            std::memcpy(&temp, &value, sizeof(value));
            temp = ((temp & 0x000000FFU) << 24) |
                   ((temp & 0x0000FF00U) << 8)  |
                   ((temp & 0x00FF0000U) >> 8)  |
                   ((temp & 0xFF000000U) >> 24);
            std::memcpy(&value, &temp, sizeof(value));
            return value;
        }
        else
        {
            return static_cast<T>(
                ((value & 0x000000FFU) << 24) |
                ((value & 0x0000FF00U) << 8)  |
                ((value & 0x00FF0000U) >> 8)  |
                ((value & 0xFF000000U) >> 24)
                );
        }
    }
    else if constexpr (sizeof(T) == 8)
    {
        if constexpr (std::is_floating_point_v<T>)
        {
            uint64_t temp;
            std::memcpy(&temp, &value, sizeof(value));
            temp = ((temp & 0x00000000000000FFULL) << 56) |
                   ((temp & 0x000000000000FF00ULL) << 40) |
                   ((temp & 0x0000000000FF0000ULL) << 24) |
                   ((temp & 0x00000000FF000000ULL) << 8)  |
                   ((temp & 0x000000FF00000000ULL) >> 8)  |
                   ((temp & 0x0000FF0000000000ULL) >> 24) |
                   ((temp & 0x00FF000000000000ULL) >> 40) |
                   ((temp & 0xFF00000000000000ULL) >> 56);
            std::memcpy(&value, &temp, sizeof(value));
            return value;
        }
        else
        {
            using UT = std::make_unsigned_t<T>;
            UT v = static_cast<UT>(value);
            v = ((v & 0x00000000000000FFULL) << 56) |
                ((v & 0x000000000000FF00ULL) << 40) |
                ((v & 0x0000000000FF0000ULL) << 24) |
                ((v & 0x00000000FF000000ULL) << 8)  |
                ((v & 0x000000FF00000000ULL) >> 8)  |
                ((v & 0x0000FF0000000000ULL) >> 24) |
                ((v & 0x00FF000000000000ULL) >> 40) |
                ((v & 0xFF00000000000000ULL) >> 56);
            return static_cast<T>(v);
        }
    }
}

template <typename T>
constexpr T FromBigEndian(T value)
{
    return ToBigEndian(value);
}

}
#endif // TOOLS_ENDIAN_H
